package cn.sq.musicserver.config.shiro.realm;




import cn.sq.musicserver.config.shiro.jwt.JWTUtil;
import cn.sq.musicserver.config.shiro.token.SqAuthenticationToken;
import cn.sq.musicserver.user.entity.SqUser;
import cn.sq.musicserver.user.service.ISqUserService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 登录的Realm用来登录验证 只在登录时候使用
 * 其他时候使用token认证
 */
@Service("loginRealm")
public class LoginRealm  extends AuthorizingRealm  {
    private  final Logger logger = LoggerFactory.getLogger(LoginRealm.class);

    @Autowired
    ISqUserService iSqUserService;


    /**
     * 大坑！，必须重写此方法，不然Shiro会报错
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof SqAuthenticationToken;
    }

    /**
     * 权限认证
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        String email = JWTUtil.getUsername(principalCollection.toString(),"email");
        //获取登录用户的信息,在认证时存储的是ShiroUser 所以得到的就是ShiroUser
        //在其他地方也可通过SecurityUtils.getSubject().getPrincipals()获取用户信息
        //SqUser user =  (SqUser) principalCollection.getPrimaryPrincipal();
        //权限字符串
        List<String> permissions=iSqUserService.findUserPermissionByUserEmail(email);
        List<String> user_role_by_username = iSqUserService.findUserRoleByUserEmail(email);

        //从数据库中获取对应权限字符串并存储permissions
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.addStringPermissions(permissions);
        simpleAuthorizationInfo.addRoles(user_role_by_username);
        //logger.debug("用户权限认证");
        return simpleAuthorizationInfo;
    }

    /**
     * 登录验证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        String token = authenticationToken.getCredentials().toString();
        // 解密获得username，用于和数据库进行对比
        String username = JWTUtil.getUsername(token,"email");
        if (username == null) {
            logger.debug("根据token没找到用户名");
            throw new AuthenticationException("token invalid");
        }

        SqUser user = iSqUserService.getOne(new QueryWrapper<SqUser>().eq("UserEmail",username));
        if (user == null) {
            logger.debug("数据库查询无此用户用户名为："+username);
            throw new AuthenticationException("User didn't existed!");
        }

        if (! JWTUtil.verify(token, username, user.getUserPassword(),"email")) {
            logger.debug("用户名或者密码错误用户名为："+username);
            throw new AuthenticationException("Username or password error");
        }

        return new SimpleAuthenticationInfo(token, token, "login_realm");
    }

    /**
     * 重写方法,清除当前用户的的 授权缓存
     * @param principals
     */
    @Override
    public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
        super.clearCachedAuthorizationInfo(principals);
    }

    /**
     * 重写方法，清除当前用户的 认证缓存
     * @param principals
     */
    @Override
    public void clearCachedAuthenticationInfo(PrincipalCollection principals) {
        super.clearCachedAuthenticationInfo(principals);
    }

    @Override
    public void clearCache(PrincipalCollection principals) {
        super.clearCache(principals);
    }

    /**
     * 自定义方法：清除所有 授权缓存
     */
    public void clearAllCachedAuthorizationInfo() {
        getAuthorizationCache().clear();
    }

    /**
     * 自定义方法：清除所有 认证缓存
     */
    public void clearAllCachedAuthenticationInfo() {
        getAuthenticationCache().clear();
    }

    /**
     * 自定义方法：清除所有的  认证缓存  和 授权缓存
     */
    public void clearAllCache() {
        clearAllCachedAuthenticationInfo();
        clearAllCachedAuthorizationInfo();
    }



}
